/*
 * =====================================================================================
 *
 *       Filename:  manifold_node.cc
 *
 *    Description:  This is a simple frontenf for using IRIS with pktgen and
 *    routers for diff topologies
 *    Can run either single threaded or on two logical processes using MPI.
 *
 *        Version:  1.0
 *        Created:  04/20/2010 02:59:08 AM
 *       Revision:  none
 *       Compiler:  mpicxx
 *
 *         Author:  Mitchelle Rasquinha (), mitchelle.rasquinha@gatech.edu
 *        Company:  Georgia Institute of Technology
 *
 * =====================================================================================
 */

#include        "iris/interfaces/irisTerminal.h"
#include        "iris/interfaces/irisInterface.h"
#include        "iris/interfaces/irisRouter.h"
#include        "iris/topology/topology.h"

#include        "kernel/clock.h"
#include        "kernel/manifold.h"
#include        "kernel/component.h"

#include        "uarch/node_terminal.h"
#include        "uarch/node_to_iris_module.h"
#include        "uarch/sim.h"

#include        "iris/topology/topo_creator.h"
#include        "sim_trace.h"
#include	"mpi.h"
#define         TOT_PROCS 1

using namespace manifold::kernel;

int Mytid; //task id
FILE* log_file;

Clock* master_clock = new manifold::kernel::Clock(1);
extern Simulator Sim;

int
main ( int argc, char *argv[] )
{
    Manifold::Init(argc,argv);

    //make sure only 2 tasks are started.
    if( TOT_PROCS != manifold::kernel::TheMessenger.get_node_size()) {
        cerr << "Please specify \"-np 2\" for mpirun!" << endl;
        return 1;
    }

    MPI_Comm_rank(MPI_COMM_WORLD, &Mytid);

    ullint sim_start_time = time(NULL);
    if(argc<3)
    {
        cout << "Error: Requires config file for input parameters\n";
        return 1;
    }

    //topology creator creates network interfaces and routers and connect them.
    Topology* tp;
    try {
	tp = TopoCreator :: create_topology(argv[1]);
    }
    catch (CreateTopologyException e) {
        cout << e.what() << endl;
	exit(1);
    }

    assert( tp != NULL );
    Sim.tp = tp;
    //create PktGens and connect them with network interfaces.
    for(int i=0; i<tp->no_nodes; i++) {
	CompId_t id = Component::Create<NodeTerminal>(0, i);
	IrisTerminal* term = dynamic_cast<NodeTerminal*>(Component::GetComponent(id));
        term->parse_config(tp->params);
        if(term)
	    tp->connect_terminal(term);
    }
    sim_main(atoi(argv[2]));

    //MPI_Barrier(MPI_COMM_WORLD);   // All components have finished Init
    std::cerr << "\n############# Start Timing Simulation for " << tp->max_simtime << " cycles Proc:"<< Mytid;

//    Manifold::StopAt(tp->max_simtime);
//    Manifold::Run();
    Sim.run();

    tp->print_noc_stats();
    MPI_Barrier(MPI_COMM_WORLD);
    if ( Mytid == TOT_PROCS-1 )
    {
        ullint sim_time_ms = (time(NULL) - sim_start_time);
        cerr << "\n\n************** Simulation Stats ***************\n";
        cerr << " Simulation Time: " << sim_time_ms << endl;
    }

    MPI_Finalize();
}


